﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Web;

namespace XXZPrint.Models.DataOperation
{
    /// <summary>
    /// 构建动态查询表达式
    /// </summary>
    public class C_BuildExpression
    {
        /// <summary>
        /// 返回一个1=1的where条件
        /// </summary>
        /// <typeparam name="T">实体对象</typeparam>
        /// <returns></returns>
        public static Expression<Func<T, bool>> True<T>()
        {
            var iType = typeof(T);
            var iwhere = Expression.Parameter(iType, "w");
            var ileft = Expression.Constant(1);
            var iright = Expression.Constant(1);
            var iExp = Expression.Equal(ileft, iright);

            return Expression.Lambda<Func<T, bool>>(iExp, iwhere);
        }

        public static Expression<Func<T,bool>> BuildExpression<T>(List<Em_Query> Querys)
        {
            var iType = typeof(T);
            var iwhere = Expression.Parameter(iType, "w");
            Expression iExp = null;
            if (Querys.Count <= 0)
            {
                var ileft = Expression.Constant(1);
                var iright = Expression.Constant(1);
                iExp = Expression.Equal(ileft, iright);

                return Expression.Lambda<Func<T, bool>>(iExp, iwhere);
            }

            foreach (Em_Query iEm_Q in Querys)
            {
                var ileft = Expression.PropertyOrField(iwhere, iEm_Q.FieldName);
                Type iFileType = GetFileType(iType,iEm_Q.FieldName);
                var iright = Expression.Constant(iEm_Q.Value, iFileType);
                Expression iem_q_ex = null;
                switch (iEm_Q.Operator)
                {
                    case Em_Operator.Include:
                        {
                            MethodInfo iMothod;
                            if (iFileType == typeof(int))
                            {
                                iMothod = typeof(int).GetMethod("Contains");
                            }
                            else
                            {
                                iMothod = typeof(string).GetMethod("Contains");
                            }
                            iem_q_ex = Expression.Call(ileft, iMothod, iright);
                            break;
                        }
                    case Em_Operator.LikeBoth:
                        {
                            if (iFileType == typeof(string))
                            {
                                iem_q_ex = Expression.Call(ileft, iFileType.GetMethod("Contains"), iright);
                            }
                            break;
                        }
                    case Em_Operator.LikeLeft:
                        {
                            if (iFileType == typeof(string))
                            {
                                iem_q_ex = Expression.Call(ileft, iFileType.GetMethod("EndsWith"), iright);
                            }
                            break;
                        }
                    case Em_Operator.LikeRight:
                        {
                            if (iFileType == typeof(string))
                            {
                                iem_q_ex = Expression.Call(ileft, iFileType.GetMethod("StartsWith"), iright);
                            }
                            break;
                        }
                    case Em_Operator.Equal:
                        {
                            iem_q_ex = Expression.Equal(ileft, iright);
                            break;
                        }
                    case Em_Operator.GtEqual:
                        {
                            iem_q_ex = Expression.GreaterThanOrEqual(ileft, iright);
                            break;
                        }
                    case Em_Operator.Gt:
                        {
                            iem_q_ex = Expression.GreaterThan(ileft, iright);
                            break;
                        }
                    case Em_Operator.LtEqual:
                        {
                            iem_q_ex = Expression.LessThanOrEqual(ileft, iright);
                            break;
                        }
                    case Em_Operator.Lt:
                        {
                            iem_q_ex = Expression.LessThan(ileft, iright);
                            break;
                        }
                    case Em_Operator.NotEqual:
                        {
                            iem_q_ex = Expression.NotEqual(ileft, iright);
                            break;
                        }
                }
                if (iExp == null)
                {
                    iExp = iem_q_ex;
                }
                else
                {
                    switch (iEm_Q.Connector)
                    {
                        case Em_Connector.And:
                            {
                                iExp = Expression.And(iExp, iem_q_ex);
                                break;
                            }
                        case Em_Connector.Or:
                            {
                                iExp = Expression.Or(iExp, iem_q_ex);
                                break;
                            }
                    }
                }
            }

            return Expression.Lambda<Func<T, bool>>(iExp, iwhere);
        }

        /// <summary>
        /// 获取对象的指定属性的类型
        /// </summary>
        /// <typeparam name="T">指定对象</typeparam>
        /// <param name="FileName">属性名称</param>
        /// <returns></returns>
        public static Type GetFileType(Type type, string FileName)
        {
            PropertyInfo[] iparameters = type.GetProperties();
            foreach (PropertyInfo ip in iparameters)
            {
                if (ip.Name == FileName)
                {
                    return ip.PropertyType;
                }
            }
            return null;
        }
    }

    /// <summary>
    /// 各组条件之间的连接符
    /// </summary>
    public enum Em_Connector
    {
        And = 0,
        Or = 1
    }

    /// <summary>
    /// 操作符
    /// </summary>
    public enum Em_Operator
    {
        [Description("IN")]
        Include = 0,
        [Description("NOT IN")]
        NotInclude = 1,
        [Description("=")]
        Equal = 2,
        [Description(">=")]
        GtEqual = 3,
        [Description(">")]
        Gt = 4,
        [Description("<=")]
        LtEqual = 5,
        [Description("<")]
        Lt = 6,
        [Description("<>")]
        NotEqual = 7,
        [Description("Like '%str%'")]
        LikeBoth = 8,
        [Description("Like '%str'")]
        LikeLeft = 9,
        [Description("Like 'str%'")]
        LikeRight = 10
    }

    /// <summary>
    /// 查询条件实体
    /// </summary>
    public class Em_Query
    {
        /// <summary>
        /// 查询字段名称
        /// </summary>
        public string FieldName { get; set; }

        /// <summary>
        /// 查询内容
        /// </summary>
        public object Value { get; set; }

        /// <summary>
        /// 查询操作符
        /// </summary>
        public Em_Operator Operator { get; set; }

        /// <summary>
        /// 连接符
        /// </summary>
        public Em_Connector Connector { get; set; }
    }
}